package auth

import (
	"fmt"
	"gitee.com/aldrice/monitor/api/common"
	"gitee.com/aldrice/monitor/configs"
	"gitee.com/aldrice/monitor/ent/user"
	"gitee.com/aldrice/monitor/internal/router"
	"gitee.com/aldrice/monitor/pkg/crypto"
	"gitee.com/aldrice/monitor/pkg/validating"
)

type userRegisterReq struct {
	Username string `json:"username" validate:"required"`
	Password string `json:"password" validate:"required"`
	Email    string `json:"email" validate:"required"`
}

var (
	errUserAlreadyExist = router.ApiError(10001, "user already exist")
)

func Register(c *router.Context) error {
	req := new(userRegisterReq)
	if err := c.Bind(req); err != nil {
		return err
	}
	if err := c.Validate(req); err != nil {
		return err
	}

	if err := validating.ValidatePasswordFunc(req.Password); err != nil {
		return fmt.Errorf("invalid password format")
	}
	if err := validating.ValidateUsername(req.Username); err != nil {
		return fmt.Errorf("invalid username format")
	}

	db, ctx := c.DB(), c.Ctx()

	// verify the existence of username
	exist, err := db.User.Query().Where(user.UsernameEqualFold(req.Username)).Exist(ctx)
	if err != nil {
		return err
	}
	if exist {
		return errUserAlreadyExist
	}

	// crypto the password then store it into db
	cipherText, err := crypto.EncryptPassword(req.Password)
	if err != nil {
		return err
	}

	// create user
	u, err := db.User.Create().SetUsername(req.Username).SetPassword(cipherText).SetEmail(req.Email).Save(ctx)
	if err != nil {
		return err
	}

	// send user jwt
	if err := sendUserAuthToken(c, u.ID); err != nil {
		return err
	}

	return c.ApiSuccess(c.Response().Header().Get("x-issued-token"))
}

func sendUserAuthToken(c *router.Context, uid int) error {
	sign, err := common.CreateSign(uid, 0, configs.LoginSecKey, configs.JwtLoginExpiredTime)
	if err != nil {
		return err
	}
	c.Response().Header().Add("x-issued-token", sign)
	return nil
}
